package io.renren.common.utils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.SqlDateConverter;
import org.apache.commons.lang.StringUtils;

/**
 * 操作bean属性的工具类，继承自BeanUtils
 * 
 * @author chenjl
 * @version 2015年5月7日 下午2:59:00
 */
public class BeanUtil extends org.apache.commons.beanutils.BeanUtils {
	// 解决BigDecimal类型值为空时的转化BUG 2015-5-17
	private static final BigDecimal BIGDECIMAL_ZERO = new BigDecimal("0");
	static {
		// 这里一定要注册默认值，使用null也可以
		BigDecimalConverter bd = new BigDecimalConverter(BIGDECIMAL_ZERO);
		ConvertUtils.register(bd, java.math.BigDecimal.class);
		// 注册sql.date的转换器，即允许BeanUtils.copyProperties时的源目标的sql类型的值允许为空
		ConvertUtils.register(new SqlDateConverter(null), java.util.Date.class);
		// ConvertUtils.register(new SqlTimestampConverter(),
		// java.sql.Timestamp.class);
		// 注册util.date的转换器，即允许BeanUtils.copyProperties时的源目标的util类型的值允许为空
		ConvertUtils.register(new DateConvert(), java.util.Date.class);
	}

	private static void convert(Object dest, Object orig) {
		if (dest == null) {
			throw new IllegalArgumentException("No destination bean specified");
		}
		if (orig == null) {
			throw new IllegalArgumentException("No origin bean specified");
		}
		if (orig instanceof DynaBean) {
			DynaProperty origDescriptors[] = ((DynaBean) orig).getDynaClass().getDynaProperties();
			for (int i = 0; i < origDescriptors.length; i++) {
				String name = origDescriptors[i].getName();
				if (PropertyUtils.isWriteable(dest, name)) {
					Object value = ((DynaBean) orig).get(name);
					try {
						copyProperty(dest, name, value);
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					}
				}
			}
		} else if (orig instanceof Map) {
			Iterator names = ((Map) orig).keySet().iterator();
			while (names.hasNext()) {
				String name = (String) names.next();
				if (PropertyUtils.isWriteable(dest, name)) {
					Object value = ((Map) orig).get(name);
					try {
						copyProperty(dest, name, value);
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					}
				}
			}
		} else {
			PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(orig);
			for (int i = 0; i < origDescriptors.length; i++) {
				String name = origDescriptors[i].getName();
				if ("class".equals(name)) {
					continue;
				}
				if (PropertyUtils.isReadable(orig, name) && PropertyUtils.isWriteable(dest, name)) {
					Object value;
					try {
						try {
							value = PropertyUtils.getSimpleProperty(orig, name);
							copyProperty(dest, name, value);
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						} catch (InvocationTargetException e) {
							e.printStackTrace();
						}

					} catch (NoSuchMethodException e) {
						e.printStackTrace();
					}

				}
			}
		}

	}

	/**
	 * 对象拷贝 数据对象空值不拷贝到目标对象
	 * 
	 * @param dataObject
	 * @param toObject
	 * @throws NoSuchMethodException
	 *             copy
	 */
	public static void copyBeanNotNull2Bean(Object databean, Object tobean) {
		PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(databean);
		for (int i = 0; i < origDescriptors.length; i++) {
			String name = origDescriptors[i].getName();
			if ("class".equals(name)) {
				continue; // No point in trying to set an object's class
			}
			if (PropertyUtils.isReadable(databean, name) && PropertyUtils.isWriteable(tobean, name)) {
				Object value;
				try {
					value = PropertyUtils.getSimpleProperty(databean, name);

					if (value != null) {
						copyProperty(tobean, name, value);
					}

				} catch (IllegalAccessException e) {

					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				}

			}
		}
	}

	/**
	 * 对象拷贝 数据对象空值不拷贝到目标对象
	 * 
	 * @param dataObject
	 * @param toObject
	 * @throws NoSuchMethodException
	 *             copy
	 */
	public static void copyBeanNotEmpty2Bean(Object databean, Object tobean) {
		PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(databean);
		for (int i = 0; i < origDescriptors.length; i++) {
			String name = origDescriptors[i].getName();
			if ("class".equals(name)) {
				continue; // No point in trying to set an object's class
			}
			if (PropertyUtils.isReadable(databean, name) && PropertyUtils.isWriteable(tobean, name)) {
				Object value;
				try {
					value = PropertyUtils.getSimpleProperty(databean, name);

					if (value != null && !value.equals("")) {
						copyProperty(tobean, name, value);
					}

				} catch (IllegalAccessException e) {

					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				}

			}
		}
	}

	/**
	 * 把orig和dest相同属性的value复制到dest中
	 * 
	 * @param dest
	 * @param orig
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void copyBean2Bean(Object dest, Object orig) {
		convert(dest, orig);
	}

	public static void copyBean2Map(Map map, Object bean) {
		PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(bean);
		for (int i = 0; i < pds.length; i++) {
			PropertyDescriptor pd = pds[i];
			String propname = pd.getName();
			Object propvalue;
			try {
				propvalue = PropertyUtils.getSimpleProperty(bean, propname);
				map.put(propname, propvalue);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			}

		}
	}

	/**
	 * 将Map内的key与Bean中属性相同的内容复制到BEAN中
	 * 
	 * @param bean
	 *            Object
	 * @param properties
	 *            Map
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void copyMap2Bean(Object bean, Map properties) {
		// Do nothing unless both arguments have been specified
		if ((bean == null) || (properties == null)) {
			return;
		}
		// Loop through the property name/value pairs to be set
		Iterator names = properties.keySet().iterator();
		while (names.hasNext()) {
			String name = (String) names.next();
			// Identify the property name and value(s) to be assigned
			if (name == null) {
				continue;
			}
			Object value = properties.get(name);
			try {
				Class clazz = null;
				try {
					clazz = PropertyUtils.getPropertyType(bean, name);
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if (null == clazz) {
					continue;
				}
				String className = clazz.getName();
				if (className.equalsIgnoreCase("java.sql.Timestamp")) {
					if (value == null || value.equals("")) {
						continue;
					}
				}
				try {
					setProperty(bean, name, value);
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} catch (NoSuchMethodException e) {
				continue;
			}
		}
	}

	/**
	 * 自动转Map key值大写 将Map内的key与Bean中属性相同的内容复制到BEAN中
	 * 
	 * @param bean
	 *            Object
	 * @param properties
	 *            Map
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void copyMap2Bean_Nobig(Object bean, Map properties) {
		// Do nothing unless both arguments have been specified
		if ((bean == null) || (properties == null)) {
			return;
		}
		// Loop through the property name/value pairs to be set
		Iterator names = properties.keySet().iterator();
		while (names.hasNext()) {
			String name = (String) names.next();
			// Identify the property name and value(s) to be assigned
			if (name == null) {
				continue;
			}
			Object value = properties.get(name);
			// 命名应该大小写应该敏感(否则取不到对象的属性)
			// name = name.toLowerCase();
			try {
				if (value == null) { // 不光Date类型，好多类型在null时会出错
					continue; // 如果为null不用设 (对象如果有特殊初始值也可以保留？)
				}
				Class clazz = null;
				try {
					clazz = PropertyUtils.getPropertyType(bean, name);
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if (null == clazz) { // 在bean中这个属性不存在
					continue;
				}
				String className = clazz.getName();
				// 临时对策（如果不处理默认的类型转换时会出错）
				if (className.equalsIgnoreCase("java.util.Date")) {
					value = new java.util.Date(((java.sql.Timestamp) value).getTime());// wait
																						// to
																						// do：貌似有时区问题,
																						// 待进一步确认
				}
				try {
					setProperty(bean, name, value);
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} catch (NoSuchMethodException e) {
				continue;
			}
		}
	}

	/**
	 * Map内的key与Bean中属性相同的内容复制到BEAN中 对于存在空值的取默认值
	 * 
	 * @param bean
	 *            Object
	 * @param properties
	 *            Map
	 * @param defaultValue
	 *            String
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void copyMap2Bean(Object bean, Map properties, String defaultValue) {
		// Do nothing unless both arguments have been specified
		if ((bean == null) || (properties == null)) {
			return;
		}
		// Loop through the property name/value pairs to be set
		Iterator names = properties.keySet().iterator();
		while (names.hasNext()) {
			String name = (String) names.next();
			// Identify the property name and value(s) to be assigned
			if (name == null) {
				continue;
			}
			Object value = properties.get(name);
			try {
				Class clazz = null;
				try {
					clazz = PropertyUtils.getPropertyType(bean, name);
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if (null == clazz) {
					continue;
				}
				String className = clazz.getName();
				if (className.equalsIgnoreCase("java.sql.Timestamp")) {
					if (value == null || value.equals("")) {
						continue;
					}
				}
				if (className.equalsIgnoreCase("java.lang.String")) {
					if (value == null) {
						value = defaultValue;
					}
				}
				try {
					setProperty(bean, name, value);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			} catch (NoSuchMethodException e) {
				continue;
			}
		}
	}

	/**
	 * 忽略map与bean中属性的大小写 将Map内的key与Bean中属性相同的内容复制到BEAN中
	 * 
	 * @param bean
	 *            Object
	 * @param properties
	 *            Map
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void copyMap2Bean_Nocase(Object bean, Map map) {
		// Do nothing unless both arguments have been specified
		if ((bean == null) || (map == null)) {
			return;
		}
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (int i = 0; i < propertyDescriptors.length; i++) {
				PropertyDescriptor descriptor = propertyDescriptors[i];
				String propertyName = descriptor.getName();
				String lowerPropertyName = propertyName.toLowerCase();
				Class clazz = null;
				try {
					clazz = PropertyUtils.getPropertyType(bean, propertyName);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
				if (null == clazz) {
					continue;
				}
				String className = clazz.getName();
				if (map.containsKey(lowerPropertyName)) {
					// 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
					Object value = map.get(lowerPropertyName);
					if (value == null || value.equals("")) {// 不光Date类型，好多类型在null时会出错
						continue;
					}
					// System.out.println("className--->"+className);
					if (className.equalsIgnoreCase("java.sql.Timestamp")) {
						if (value == null || value.equals("")) {
							continue;
						}
					}
					if (className.equalsIgnoreCase("java.util.Date")) {
						if (value == null || value.equals("")) {
							continue;
						}
					}
					Object[] args = new Object[1];
					args[0] = value;
					// System.out.println("value--->"+value+"  "+descriptor.getName());
					BeanUtil.setProperty(bean, propertyName, value);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public BeanUtil() {
		super();
	}
	
	/**
   * 对象拷贝
   * 将空字符串转换为null
   * 
   * @param dataObject
   * @param toObject
   * @throws NoSuchMethodException
   * copy
   */
    public static void convertEmptyStringToNull(Object databean)
    {
        if(databean != null) {
            Object tobean = databean;
            PropertyDescriptor origDescriptors[] =
                PropertyUtils.getPropertyDescriptors(databean);
            for (int i = 0; i < origDescriptors.length; i++) {
                String name = origDescriptors[i].getName();
                if ("class".equals(name)) {
                    continue; // No point in trying to set an object's class
                }
                if (PropertyUtils.isReadable(databean, name) &&
                    PropertyUtils.isWriteable(tobean, name)) {
                    Object value;
                  try {
                      value = PropertyUtils.getSimpleProperty(databean, name);
        
                      // 如果为空字符串，则将其值设置为null
                      if (value != null && value.getClass().getName().equals("java.lang.String")) {
                          if (StringUtils.isEmpty((String)value)) {
                        	  copyProperty(tobean, name, null);
                          }
                      }
                          
                  } catch (IllegalAccessException e) {
                      
                      e.printStackTrace();
                  } catch (InvocationTargetException e) {
                      e.printStackTrace();
                  } catch (NoSuchMethodException e) {
                      e.printStackTrace();
                  }
                }
            } 
        }
    }
}

class DateConvert implements Converter {
	public Object convert(Class arg0, Object arg1) {
		try {
			String p = (String) arg1;
			if (p == null || p.trim().length() == 0) {
				return null;
			}
			try {
				SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				return df.parse(p.trim());
			} catch (Exception e) {
				try {
					SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
					return df.parse(p.trim());
				} catch (ParseException ex) {
					return null;
				}
			}
		} catch (Exception e) {
			return arg1;
		}
	}
}